package com.jianggujin.redis.component;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

import javax.swing.BorderFactory;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.MenuElement;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import com.jianggujin.redis.config.ConnectionConfig;
import com.jianggujin.redis.node.RedisConnection;
import com.jianggujin.redis.node.RedisDatabase;
import com.jianggujin.redis.node.RedisKey;
import com.jianggujin.redis.node.RedisKeys;

public class ConnectionTree extends JScrollPane {
    private JTree connectionTree;
    private DefaultTreeModel connectionTreeModel;
    private DefaultMutableTreeNode connectionRootNode;

    private JPopupMenu connectionMenu;
    private JMenuItem connectMenuItem;
    private JMenuItem disconnectMenuItem;
    private JMenuItem infoMenuItem;
    private JMenuItem propertyMenuItem;
    private JMenuItem clientsMonitorMenuItem;
    private JMenuItem removeMenuItem;

    private JPopupMenu databaseMenu;
    private JMenuItem addNewKeyMenuItem;
    private JMenuItem reloadKeysMenuItem;
    private JMenuItem filterKeysMenuItem;
    private JMenuItem resetKeysFilterMenuItem;
    private JMenuItem commandMenuItem;

    private JPopupMenu keyMenu;
    private JMenuItem deleteKeyMenuItem;
    private JMenuItem setTTLMenuItem;
    private JMenuItem removeTTLMenuItem;
    private JMenuItem watchMenuItem;

    private JPopupMenu keysMenu;
    private JMenuItem deleteKeysMenuItem;

    private volatile Map<TreeNode, TreePath> expandTreeMap = new LinkedHashMap<>();
    private ConnectionListener listener;

    public ConnectionTree() {
        connectionRootNode = new DefaultMutableTreeNode("");
        connectionTreeModel = new DefaultTreeModel(connectionRootNode);
        connectionTree = new JTree(connectionTreeModel);
        connectionTree.setRootVisible(false);
        connectionTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        connectionTree.addTreeSelectionListener(e -> handleSelectClientOrKey(e));

        initConnectionMenu();
        initDatabaseMenu();
        initKeyMenu();
        initKeysMenu();

        connectionTree.addMouseListener(new MouseAdapter() {
            private void processPopTrigger(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    handleConnectionTreeContextMenu(e);
                }
            }

            @Override
            public void mousePressed(MouseEvent e) {
                processPopTrigger(e);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                processPopTrigger(e);
            }

            public void mouseClicked(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() > 1) {
                    handleConnectionTreeDbClick(e);
                }
            }
        });
        setViewportView(connectionTree);
        setBorder(BorderFactory.createTitledBorder("Name"));
    }

    private void initConnectionMenu() {
        connectionMenu = new JPopupMenu();
        connectMenuItem = new JMenuItem("Connect");
        disconnectMenuItem = new JMenuItem("Disconnect");
        infoMenuItem = new JMenuItem("Info");
        propertyMenuItem = new JMenuItem("Property");
        clientsMonitorMenuItem = new JMenuItem("Clients Monitor");
        removeMenuItem = new JMenuItem("Remove");
        connectMenuItem.addActionListener(e -> handleConnect());
        disconnectMenuItem.addActionListener(e -> handleDisconnect());
        infoMenuItem.addActionListener(e -> handleInfo());
        propertyMenuItem.addActionListener(e -> handleProperty());
        clientsMonitorMenuItem.addActionListener(e -> handleClientsMonitor());
        removeMenuItem.addActionListener(e -> handleRemove());
        connectionMenu.add(connectMenuItem);
        connectionMenu.add(disconnectMenuItem);
        connectionMenu.add(infoMenuItem);
        connectionMenu.add(propertyMenuItem);
        connectionMenu.add(clientsMonitorMenuItem);
        connectionMenu.add(removeMenuItem);
    }

    private void initDatabaseMenu() {
        databaseMenu = new JPopupMenu();
        addNewKeyMenuItem = new JMenuItem("Add New Key");
        reloadKeysMenuItem = new JMenuItem("Load/Reload");
        filterKeysMenuItem = new JMenuItem("Filter Keys");
        resetKeysFilterMenuItem = new JMenuItem("Reset Keys Filter");
        commandMenuItem = new JMenuItem("Show Command Dialog");

        addNewKeyMenuItem.addActionListener(e -> handleAddNewKey());
        reloadKeysMenuItem.addActionListener(e -> handleReloadKeys());
        filterKeysMenuItem.addActionListener(e -> handleFilterKeys());
        resetKeysFilterMenuItem.addActionListener(e -> handleResetKeysFilter());
        commandMenuItem.addActionListener(e -> handleShowCommand());

        databaseMenu.add(addNewKeyMenuItem);
        databaseMenu.add(reloadKeysMenuItem);
        databaseMenu.add(filterKeysMenuItem);
        databaseMenu.add(resetKeysFilterMenuItem);
        databaseMenu.add(commandMenuItem);
    }

    private void initKeyMenu() {
        keyMenu = new JPopupMenu();
        deleteKeyMenuItem = new JMenuItem("Delete Key");
        deleteKeyMenuItem.addActionListener(e -> handleDeleteKey());
        keyMenu.add(deleteKeyMenuItem);
        setTTLMenuItem = new JMenuItem("Set TTL");
        deleteKeyMenuItem.addActionListener(e -> handleSetTTL());
        keyMenu.add(setTTLMenuItem);
        removeTTLMenuItem = new JMenuItem("Remove TTL");
        deleteKeyMenuItem.addActionListener(e -> handleRemoveTTL());
        keyMenu.add(removeTTLMenuItem);
        watchMenuItem = new JMenuItem("Watch");
        watchMenuItem.addActionListener(e -> handleWatch());
        keyMenu.add(watchMenuItem);
    }

    private void initKeysMenu() {
        keysMenu = new JPopupMenu();
        deleteKeysMenuItem = new JMenuItem("Delete Keys");
        deleteKeysMenuItem.addActionListener(e -> handleDeleteKeys());
        keysMenu.add(deleteKeysMenuItem);
    }

    /**
     * 连接redis
     * 
     * @param redisClientNode
     * @param client
     */
    private void handleConnect() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        handleConnect(selectNode);
    }

    private void handleConnect(DefaultMutableTreeNode connectionNode) {
        RedisConnection connection = getRedisConnection(connectionNode);
        connection.getClient();
        if (!connection.isValited()) {
            // ConnectionConfig config = connection.getConfig();
            if (listener != null) {
                listener.onConnectError(connection);
            }
            // MessageUtils.showErrorMessage(frame, "Connect error:" + config.getHost() +
            // ":" + config.getPort());
            return;
        }
        if (connectionNode.isLeaf()) {
            for (int i = 0; i < 16; i++) {
                connectionNode.add(new DefaultMutableTreeNode(new RedisDatabase(connection, i)));
            }
        }
        if (listener != null) {
            listener.onConnectSuccess(connection);
        }
    }

    /**
     * 断开连接redis
     * 
     */
    private void handleDisconnect() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        RedisConnection connection = getRedisConnection(selectNode);
        connection.disconnect();
        if (listener != null) {
            listener.onDisconnect(connection);
        }
    }

    /**
     * 显示Info
     */
    private void handleInfo() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        if (listener != null) {
            listener.handleInfo(getRedisConnection(selectNode));
        }
    }

    /**
     * 显示Property
     */
    public void handleProperty() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        if (listener != null) {
            listener.handleProperty(getRedisConnection(selectNode));
        }
    }

    /**
     * 显示ClientsMonitor
     */
    public void handleClientsMonitor() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        if (listener != null) {
            listener.handleClientsMonitor(getRedisConnection(selectNode));
        }
    }

    /**
     * 移除连接
     */
    public void handleRemove() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        RedisConnection connection = getRedisConnection(selectNode);
        connection.disconnect();
        recordExpandNode(connectionRootNode);
        selectNode.removeFromParent();
        handleReloadNodeTree(connectionRootNode);
        if (listener != null) {
            listener.onDisconnect(connection);
            listener.onRemove(connection);
        }
    }

    /**
     * 添加新的键
     */
    private void handleAddNewKey() {
        if (listener != null) {
            listener.handleAddNewKey();
        }
    }

    /**
     * 重载键
     */
    private void handleReloadKeys() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        handleLoadOrReloadNode(selectNode);
        if (listener != null) {
            listener.onReloadKeys(getRedisDatabase(selectNode));
        }
    }

    /**
     * 过滤键值
     */
    private void handleFilterKeys() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        if (listener != null) {
            listener.handleFilterKeys(selectNode);
        }
    }

    public void setFilterKeys(DefaultMutableTreeNode databaseNode, String filter) {
        if (databaseNode == null || filter == null || filter.length() == 0) {
            return;
        }
        RedisDatabase database = getRedisDatabase(databaseNode);
        database.setFilter(filter);
        handleLoadOrReloadNode(databaseNode);
        if (listener != null) {
            listener.onFilterKeys(database);
        }
    }

    /**
     * 重置键值过滤器
     */
    private void handleResetKeysFilter() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        RedisDatabase database = getRedisDatabase(selectNode);
        database.resetFilter();
        handleLoadOrReloadNode(selectNode);
        if (listener != null) {
            listener.onResetKeysFilter(database);
        }
    }

    /**
     * 显示命令对话框
     */
    private void handleShowCommand() {
    }

    /**
     * 删除键
     */
    private void handleDeleteKey() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        RedisKey redisKey = (RedisKey) selectNode.getUserObject();
        RedisDatabase database = redisKey.getDatabase();
        RedisConnection client = database.getRedisConnection();
        Long l = client.getClient().del(redisKey.getKey());
        Boolean exists = null;
        if ((l != null && l == 1) || ((exists = client.getClient().exists(redisKey.getKey())) == null || !exists)) {
            DefaultMutableTreeNode node = selectNode;
            while (node.getChildCount() == 0 && !(node.getUserObject() instanceof RedisDatabase)) {
                DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
                node.removeFromParent();
                node = parent;
            }
            recordExpandNode(node);
            handleReloadNodeTree(node);
            if (listener != null) {
                listener.onDeleteKeySuccess(redisKey);
            }
        } else {
            if (listener != null) {
                listener.onDeleteKeyError(redisKey);
            }
        }
    }

    private void handleSetTTL() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        RedisKey redisKey = (RedisKey) selectNode.getUserObject();
        RedisDatabase database = redisKey.getDatabase();
        RedisConnection client = database.getRedisConnection();
        if (listener != null) {
            listener.handleSetTTL(selectNode, client.getClient().ttl(redisKey.getKey()));
        }
    }

    public void setTTL(DefaultMutableTreeNode redisKeyNode, String ttl) {
        if (redisKeyNode == null || ttl == null || ttl.matches("\\d+")) {
            return;
        }
        RedisKey redisKey = (RedisKey) redisKeyNode.getUserObject();
        RedisDatabase database = redisKey.getDatabase();
        RedisConnection client = database.getRedisConnection();
        client.getClient().expire(redisKey.getKey(), Integer.parseInt(ttl));
        if (listener != null) {
            listener.handleSelectRedisKey(redisKey);
        }
    }

    private void handleRemoveTTL() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        RedisKey redisKey = (RedisKey) selectNode.getUserObject();
        RedisDatabase database = redisKey.getDatabase();
        RedisConnection client = database.getRedisConnection();
        client.getClient().persist(redisKey.getKey());
        if (listener != null) {
            listener.handleSelectRedisKey(redisKey);
        }
    }

    private void handleWatch() {
    }

    /**
     * 删除多个键
     */
    private void handleDeleteKeys() {
        DefaultMutableTreeNode selectNode = getSelectNode();
        if (selectNode == null) {
            return;
        }
        RedisKeys redisKeys = (RedisKeys) selectNode.getUserObject();
        RedisDatabase database = redisKeys.getDatabase();
        RedisConnection client = database.getRedisConnection();
        List<DefaultMutableTreeNode> keys = new ArrayList<DefaultMutableTreeNode>();
        findRedisKey(selectNode, keys);
        List<RedisKey> deleteKeys = new ArrayList<RedisKey>(keys.size());
        Long l = client.getClient().del(keys.stream().map(item -> ((RedisKey) item.getUserObject()).getKey())
                .collect(Collectors.toList()).toArray(new String[0]));
        if (l != null && l == keys.size()) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectNode.getParent();
            selectNode.removeFromParent();
            while (node.getChildCount() == 0 && !(node.getUserObject() instanceof RedisDatabase)) {
                DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
                node.removeFromParent();
                node = parent;
            }
            recordExpandNode(node);
            handleReloadNodeTree(node);
            if (listener != null) {
                for (DefaultMutableTreeNode treeNode : keys) {
                    deleteKeys.add((RedisKey) treeNode.getUserObject());
                }
                listener.onDeleteKeys(redisKeys, keys, deleteKeys);
            }
        } else {
            for (DefaultMutableTreeNode key : keys) {
                RedisKey redisKey = (RedisKey) key.getUserObject();
                Boolean exists = client.getClient().exists(redisKey.getKey());
                // 删除
                if (exists == null || !exists) {
                    deleteKeys.add(redisKey);
                    DefaultMutableTreeNode node = key;
                    while (node.getChildCount() == 0 && !(node.equals(selectNode))) {
                        DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
                        node.removeFromParent();
                        node = parent;
                    }
                }
            }
            DefaultMutableTreeNode node = selectNode;
            while (node.getChildCount() == 0 && !(node.getUserObject() instanceof RedisDatabase)) {
                DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
                node.removeFromParent();
                node = parent;
            }
            recordExpandNode(node);
            handleReloadNodeTree(node);
            if (listener != null) {
                listener.onDeleteSomeKeys(redisKeys, keys, deleteKeys);
            }
        }
    }

    private void findRedisKey(DefaultMutableTreeNode node, List<DefaultMutableTreeNode> keys) {
        if (node.isLeaf()) {
            Object userObject = node.getUserObject();
            if (userObject instanceof RedisKey) {
                keys.add(node);
            }
        } else {
            for (Enumeration<?> e = node.children(); e.hasMoreElements();) {
                findRedisKey((DefaultMutableTreeNode) e.nextElement(), keys);
            }
        }
    }

    private void handleLoadOrReloadNode(DefaultMutableTreeNode selectNode) {
        RedisDatabase database = getRedisDatabase(selectNode);
        RedisConnection client = database.getRedisConnection();
        client.getClient().select(database.getDbIndex());
        Set<String> keys = null;
        if (database.hasFilter()) {
            keys = client.getClient().keys(database.getFilter());
        } else {
            keys = client.getClient().keys(client.getConfig().getKeysGlobStylePattern());
        }
        handleLoadOrReloadNode(client.getConfig().getNamespaceSeparator(), keys, selectNode, database);
        handleReloadNodeTree(selectNode);
    }

    private void handleLoadOrReloadNode(char namespaceSeparator, Set<String> keys, DefaultMutableTreeNode selectNode,
            RedisDatabase database) {
        selectNode.removeAllChildren();
        if (keys != null) {
            keys.stream().sorted().forEach(key -> {
                int preIndex = 0, len = key.length(), pos = 0;
                DefaultMutableTreeNode node = null;
                for (; pos < len; pos++) {
                    if (key.charAt(pos) == namespaceSeparator) {
                        String item = key.substring(preIndex, pos);
                        node = findOrCreateNodeByUserObject(node == null ? selectNode : node,
                                new RedisKeys(database, item));
                        preIndex = pos + 1;
                    }
                }
                if (preIndex < len) {
                    node = findOrCreateNodeByUserObject(node == null ? selectNode : node,
                            new RedisKeys(database, key.substring(preIndex)));
                }
                RedisKeys userObject = (RedisKeys) node.getUserObject();
                node.setUserObject(new RedisKey(database, userObject.getItem(), key));
            });
        }
    }

    private DefaultMutableTreeNode findOrCreateNodeByUserObject(DefaultMutableTreeNode parent, RedisKeys item) {
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            DefaultMutableTreeNode child = (DefaultMutableTreeNode) parent.getChildAt(i);
            if (item.equals(child.getUserObject())) {
                return child;
            }
        }
        DefaultMutableTreeNode node = new DefaultMutableTreeNode(item);
        parent.add(node);
        return node;
    }

    /**
     * 重新加载节点
     * 
     * @param node
     */
    private synchronized void handleReloadNodeTree(TreeNode node) {
        if (node == null) {
            return;
        }
        connectionTreeModel.reload(node);
        for (Entry<TreeNode, TreePath> entry : expandTreeMap.entrySet()) {
            connectionTree.expandPath(entry.getValue());
        }
        expandTreeMap.clear();
        if (listener != null) {
            listener.onReloadTree();
        }
    }

    /**
     * 记录指定节点下所有展开的节点
     * 
     * @param node
     */
    private synchronized void recordExpandNode(TreeNode node) {
        if (node.getChildCount() > 0) {
            TreePath treePath = new TreePath(connectionTreeModel.getPathToRoot(node));
            if (connectionTree.isExpanded(treePath)) {
                expandTreeMap.put(node, treePath);
            }
            for (Enumeration<?> e = node.children(); e.hasMoreElements();) {
                recordExpandNode((TreeNode) e.nextElement());
            }
        }
    }

    private RedisConnection getRedisConnection(DefaultMutableTreeNode connectionNode) {
        return (RedisConnection) connectionNode.getUserObject();
    }

    private RedisDatabase getRedisDatabase(DefaultMutableTreeNode databaseNode) {
        return (RedisDatabase) databaseNode.getUserObject();
    }

    /**
     * 获得当前选择的节点
     * 
     * @return
     */
    private DefaultMutableTreeNode getSelectNode() {
        TreePath treePath = connectionTree.getSelectionPath();
        if (treePath == null) {
            return null;
        }
        return (DefaultMutableTreeNode) treePath.getLastPathComponent();
    }

    /**
     * 客户端或键值被选择事件
     * 
     * @param e
     */
    private void handleSelectClientOrKey(TreeSelectionEvent e) {
        TreePath treePath = e.getNewLeadSelectionPath();
        if (treePath == null) {
            return;
        }
        DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
        // 只处理叶子节点
        if (treeNode.isLeaf()) {
            Object userObject = treeNode.getUserObject();
            // 确保该叶子节点为Redis的键值节点
            if (userObject instanceof RedisKey) {
                if (listener != null) {
                    listener.handleSelectRedisKey((RedisKey) userObject);
                }
            }
        }
    }

    /**
     * 树组件上下文菜单
     * 
     * @param e
     */
    private void handleConnectionTreeContextMenu(MouseEvent e) {
        TreePath path = connectionTree.getPathForLocation(e.getX(), e.getY());
        if (path == null) {
            return;
        }
        connectionTree.setSelectionPath(path);
        DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        Object userObject = treeNode.getUserObject();
        if (userObject instanceof RedisConnection) {
            handleShowRedisConnectionContextMenu(e, (RedisConnection) userObject);
            return;
        }
        if (userObject instanceof RedisDatabase) {
            handleShowRedisDatabaseContextMenu(e, (RedisDatabase) userObject);
            return;
        }
        if (userObject instanceof RedisKey) {
            handleShowRedisKeyContextMenu(e, (RedisKey) userObject);
            return;
        }
        if (userObject instanceof RedisKeys) {
            handleShowRedisKeysContextMenu(e, (RedisKeys) userObject);
            return;
        }
    }

    private void handleShowRedisConnectionContextMenu(MouseEvent e, RedisConnection client) {
        boolean isConnected = client.isValited();
        connectMenuItem.setEnabled(!isConnected);
        disconnectMenuItem.setEnabled(isConnected);
        infoMenuItem.setEnabled(isConnected);
        propertyMenuItem.setEnabled(isConnected);
        clientsMonitorMenuItem.setEnabled(isConnected);
        connectionMenu.show(connectionTree, e.getX(), e.getY());
    }

    private void handleShowRedisDatabaseContextMenu(MouseEvent e, RedisDatabase database) {
        boolean isConnected = database.getRedisConnection().isValited();
        MenuElement[] elements = databaseMenu.getSubElements();
        if (elements != null) {
            for (MenuElement element : elements) {
                ((JMenuItem) element).setEnabled(isConnected);
            }
        }
        databaseMenu.show(connectionTree, e.getX(), e.getY());
    }

    private void handleShowRedisKeyContextMenu(MouseEvent e, RedisKey redisKey) {
        boolean isConnected = redisKey.getRedisConnection().isValited();
        MenuElement[] elements = keyMenu.getSubElements();
        if (elements != null) {
            for (MenuElement element : elements) {
                ((JMenuItem) element).setEnabled(isConnected);
            }
        }
        keyMenu.show(connectionTree, e.getX(), e.getY());
    }

    private void handleShowRedisKeysContextMenu(MouseEvent e, RedisKeys redisKey) {
        boolean isConnected = redisKey.getRedisConnection().isValited();
        MenuElement[] elements = keysMenu.getSubElements();
        if (elements != null) {
            for (MenuElement element : elements) {
                ((JMenuItem) element).setEnabled(isConnected);
            }
        }
        keysMenu.show(connectionTree, e.getX(), e.getY());
    }

    private void handleConnectionTreeDbClick(MouseEvent e) {
        TreePath path = connectionTree.getPathForLocation(e.getX(), e.getY());
        if (path == null) {
            return;
        }
        DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        Object userObject = treeNode.getUserObject();
        if (userObject instanceof RedisConnection) {
            RedisConnection connection = (RedisConnection) userObject;
            if (!connection.isValited()) {
                handleConnect(treeNode);
            }
            return;
        }
        if (userObject instanceof RedisDatabase) {
            if (treeNode.isLeaf()) {
                handleLoadOrReloadNode(treeNode);
            }
            return;
        }
    }

    public void connect(ConnectionConfig config) {
        RedisConnection connection = new RedisConnection(config);
        DefaultMutableTreeNode redisClientNode = new DefaultMutableTreeNode(connection);
        connectionRootNode.add(redisClientNode);
        handleConnect(redisClientNode);
        handleReloadNodeTree(connectionRootNode);
    }

    public void disconnect() {
        int connections = connectionRootNode.getChildCount();
        for (int i = 0; i < connections; i++) {
            getRedisConnection((DefaultMutableTreeNode) connectionRootNode.getChildAt(i)).disconnect();
        }
    }

    public void setConnectionListener(ConnectionListener listener) {
        this.listener = listener;
    }

    public static interface ConnectionListener {

        void onConnectError(RedisConnection connection);

        void handleSetTTL(DefaultMutableTreeNode redisKeyNode, Long ttl);

        void handleSelectRedisKey(RedisKey redisKey);

        void onReloadTree();

        void onDeleteSomeKeys(RedisKeys redisKeys, List<DefaultMutableTreeNode> keys, List<RedisKey> deleteKeys);

        void onDeleteKeys(RedisKeys redisKeys, List<DefaultMutableTreeNode> keys, List<RedisKey> deleteKeys);

        void onDeleteKeyError(RedisKey redisKey);

        void onDeleteKeySuccess(RedisKey redisKey);

        void onResetKeysFilter(RedisDatabase database);

        void onFilterKeys(RedisDatabase database);

        void handleFilterKeys(DefaultMutableTreeNode databaseNode);

        void onReloadKeys(RedisDatabase database);

        void handleAddNewKey();

        void onRemove(RedisConnection connection);

        void handleClientsMonitor(RedisConnection connection);

        void handleProperty(RedisConnection connection);

        void handleInfo(RedisConnection connection);

        void onDisconnect(RedisConnection connection);

        void onConnectSuccess(RedisConnection connection);
    }

}
